package com.carbon.core.util;

import java.math.BigDecimal;

/**
 * 存储单位转换
 *
 * @author czq
 * @date 2021-03-08
 */
public class MemoryUtils {

    private final static long RADIX = 1024;

    public enum MemoryUnit {
        /**
         * 1 byte
         */
        BYTE(1),
        /**
         * 1 KB = 1024 byte
         */
        KB(2),
        /**
         * 1  1024 KB
         */
        MB(3),
        /**
         * 1  1024 MB
         */
        GB(4),
        /**
         * 1  1024 GB
         */
        TB(5),
        /**
         * 1  1024 TB
         */
        PB(6);

        private final int value;

        MemoryUnit(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    public static long pow(long a, long b) {
        return (long) Math.pow(a, b);
    }

    /**
     * 转换单位
     * <p>
     * 默认四舍五入模式 保留 4 位小数
     *
     * @param size       当前大小
     * @param memoryUnit 当前单位
     * @param targetUnit 转换后的单位
     * @return 值 或 null
     */
    public static BigDecimal switchStorageUnit(BigDecimal size, MemoryUnit memoryUnit,
                                               MemoryUnit targetUnit) {
        return switchUnit(size, memoryUnit, targetUnit, 4, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 转换单位
     * <p>
     * 默认四舍五入模式
     *
     * @param size       当前大小
     * @param memoryUnit 当前单位
     * @param targetUnit 转换后的单位
     * @param scale      小数位
     * @return 值 或 null
     */
    public static BigDecimal switchStorageUnit(BigDecimal size, MemoryUnit memoryUnit,
                                               MemoryUnit targetUnit, int scale) {
        return switchUnit(size, memoryUnit, targetUnit, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 转换单位
     *
     * @param size         当前大小
     * @param memoryUnit   当前单位
     * @param targetUnit   转换后的单位
     * @param scale        小数位
     * @param roundingMode 保留小数方式
     * @return 值 或 null
     * @see BigDecimal
     */
    public static BigDecimal switchStorageUnit(BigDecimal size, MemoryUnit memoryUnit,
                                               MemoryUnit targetUnit, int scale, int roundingMode) {
        return switchUnit(size, memoryUnit, targetUnit, scale, roundingMode);
    }

    private static BigDecimal switchUnit(BigDecimal size, MemoryUnit memoryUnit, MemoryUnit targetUnit,
                                         int scale, int roundingMode) {
        BigDecimal result;
        if (null == size) {
            return null;
        }
        int source = memoryUnit.value;
        int target = targetUnit.value;
        if (source == target) {
            result = size;
        } else {
            if (source > target) {
                long count = pow(RADIX, (source - target));
                result = size.multiply(BigDecimal.valueOf(count));
            } else {
                long count = pow(RADIX, (target - source));
                result = size.divide(BigDecimal.valueOf(count), scale, roundingMode).stripTrailingZeros();
            }
        }
        return result;
    }
}
